Creating maintainable JavaScript code is important if want to keep using the code.
In this article, we’ll look at the basics of creating maintainable JavaScript code by looking at avoiding global variables and loosen coupling in our UI.
No Global Approach
We can create IIFEs to create private variables without any global variables.
We pass the global objects we need into the IIFE and we can use it without changing it.
For instance, we can write:
(function(win) {
const doc = win.document;
// ...
}(window));
We create our IIFE and then called with the window
object so that we can access window.document
and assign it to a variable.
Then we can do whatever we want with it.
The function wrapper can be used for scripts where we don’t want to create any global objects.
This pattern is of limited use.
Any scripts that are used by other scripts on the page can’t use this approach.
If we have small scripts that don’t interact with any other scripts, then this approach can be used.
Event Handling
Event handling is doing all the time in client-side JavaScript.
Our app has to handle events from inputs, mouse clicks, scrolling and more.
There are also lots of potentials to create tightly coupled code if we aren’t careful.
The event
object is available in the event handler functions as a parameter.
And we can easily use it to create tightly coupled code.
To make sure we don’t create tightly coupled code, we should keep a few things in mind.
Separate Application Logic
We need to separate app logic so that we don’t create app logic code that’s coupled to the UI.
App logic code that’s in the event handlers are hard to trace and test.
Also, we may end up duplicating our logic code when we can make them reusable.
And testing is harder is we create logic code that’s coupled to the event handling code.
We’ve to fire events to test our app logic code even when we just want to test the logic.
Therefore, we should separate the app logic code from the event handling code.
For instance, we can separate our app logic code from our event handles by writings:
function onClick(event) {
showPopup(event);
}
function showPopup(event) {
const popup = document.getElementById("popup");
popup.style.left = `${event.clientX}px`;
popup.style.top = `${event.clientY}px`;
popup.className = "popup";
}
const button = document.querySelector('button');
button.addEventListener('click', onClick);
We have the showPopup
function to show the popup and the onClick
method to listen to clicks on the button.
When onClick
runs showPopup
runs so that we don’t have all our logic in our event handler function.
Don’t Pass the Event Object Around
We shouldn’t pass the event object around since it depends on the element that the event handler function is called on.
We want to decouple our app logic from the DOM elements, so we shouldn’t take the event
object as a parameter in our app logic function.
Instead of taking the event
object in showPopup
, we should just take x and y coordinates.
For instance, we can write:
function onclick(event) {
const {
clientX,
clienty
} = event;
showPopup(clientX, clienty);
}
function showPopup(x, y) {
const popup = document.getElementById("popup");
popup.style.left = `${x}px`;
popup.style.top = `${y}px`;
popup.className = "popup";
}
const button = document.querySelector('button');
button.addEventListener('click', onClick);
We changed the showPopup
function to take the x and y coordinate of the popup so that we don’t have to pass the event
object to our app logic.
This keeps our event handling code loosely coupled from the app logic code.
Conclusion
We should decouple our app logic code from our event handling code.
Also, we can create IIFEs to get global variables and use them inside.